﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;

//Mark Rowe 
//From the IRDev Library Project.
namespace AutoDeploy.Common.Library
{
    ///This is the Magic Leprechaun Part of the code. 
    public static class DeployHelper
    {
        public static List<string> GetDeploymentObjectNames(XDocument x)
        {
            List<string> ls = new List<string>();
            foreach(XElement xe in x.Element("AutoDeploy").Elements("DeploymentObject"))
            {
                    ls.Add(xe.Attribute("name").Value);
            }
            return ls;
        }
        public static List<CommandSet> GetCommandSets(DeploymentObject ado)
        {
            var query = from c in ado.CommandSets
                        select c;
            return query.ToList();
        }
        public static List<string> GetDeploymentObjectNames(string uri)
        {
            XDocument x = XDocument.Load(uri);
            return GetDeploymentObjectNames(x);
        }
        public static DeploymentObject LoadDeploymentObjectFromAutoDeployConfig(string autodeployXmlURI, string deploymentObjectName)
        {
            return LoadDeploymentObjectFromAutoDeployConfig(GetDeploymentObject(autodeployXmlURI,deploymentObjectName));
        }
        public static DeploymentObject LoadDeploymentObjectFromAutoDeployConfig(XElement currentDeployment)
        {
            return DeploymentObjectFactory(currentDeployment);
        }
        public static XElement GetDeploymentObject(string autodeployXmlURI, string deploymentObjectName)
        {
           XDocument xdoc = XDocument.Load(autodeployXmlURI);
           return xdoc.Element("AutoDeploy").Elements("DeploymentObject").Where(x => x.Attribute("name").Value.Trim() == deploymentObjectName.Trim()).FirstOrDefault(); 
        }
        /// <summary>
        ///Command – doesRegistryEntryExist – to see if a registry entry exists (example:SOFTWARE/Microsoft/UDDI)
        ///Command – isInstalled – to see if they have the proper installations (example:SQL Server)
        ///Command – isServiceInstalled - to see if they have the proper service installed (example:IISADMIN)
        ///Command - Message
        ///Command - runCommandLine (EXE, COM, PS1, EXE, MSI, ZIP/UNZIP, Copy Move, Mappings can all be done here.)
        ///Command - runSQLCommand (Run Command From XML Config)
        ///Command - runSQLScript (SQL in file)
        ///Command - runIfServiceExists
        ///Command - runIfProgramInstalled
        ///Command - runIfRegistryExists
        ///Command - addXElement
        ///Command - replaceOrAddXElementIfMissing
        ///Command - replaceOrAddXAttributeIfMissing
        /// </summary>
        /// <param name="cs"></param>
        /// <param name="runAsUserName"></param>
        /// <param name="runAsPassword"></param>
        /// <param name="sqlConnectionString"></param>
        /// <returns></returns>
        public static string RunCurrentCommand(CommandSet cs, string runAsUserName, string runAsPassword, string sqlConnectionString)
        {
            string s = string.Empty;
            bool found = false;
            List<string> ls = new List<string>();
            switch (cs.Command.ToLower().Trim())
            {
                //Command – isInstalled – to see if they have the proper installations (example:SQL Server)
                case "isinstalled":
                    {
                        found = false;
                        foreach (string value in cs.Values)
                        {
                            if (value.Contains("::"))
                            {
                                if (ExternalHelper.Helper.isInstalled(value.Substring(0, value.IndexOf("::")).Trim(), bool.Parse((value.Substring(value.IndexOf("::") + 2).Trim()))))
                                {
                                    s += "Passed:" + value.Substring(0, value.IndexOf("::")).Trim() + " Found." + cs.Success + "\n";
                                    found = true;
                                }
                            }
                            else
                            {
                                if (ExternalHelper.Helper.isInstalled(value, false))
                                {
                                    s += "Passed:" + value.Substring(0, value.IndexOf("::")).Trim() + " Found." + cs.Success + "\n";
                                    found = true;
                                }
                            }
                        }
                        if (!found)
                        {
                            s = "Error:" + cs.Error + "\n";
                        }
                        break;
                    }
                //Command – isServiceInstalled - to see if they have the proper service installed (example:IISADMIN)
                case "isserviceinstalled":
                    {
                        found = false;
                        foreach (string value in cs.Values)
                        {
                            if (value.Contains("::"))
                            {
                                if (ExternalHelper.Helper.isServiceInstalled(value.Substring(0, value.IndexOf("::")).Trim(), bool.Parse((value.Substring(value.IndexOf("::") + 2).Trim()))))
                                {
                                    s += "Passed:" + value.Substring(0, value.IndexOf("::")).Trim() + " Found." + cs.Success + "\n";
                                    found = true;
                                }
                            }
                            else
                            {
                                if (ExternalHelper.Helper.isServiceInstalled(value, false))
                                {
                                    s += "Passed:" + value.Substring(0, value.IndexOf("::")).Trim() + " Found." + cs.Success + "\n";
                                    found = true;
                                }
                            }
                        }
                        if (!found)
                        {
                            s = "Error:" + cs.Error + "\n";
                        }
                        break;
                    }
                //Command – doesRegistryEntryExist – to see if a registry entry exists (example:SOFTWARE/Microsoft/UDDI)
                case "doesregistryentryexist":
                    {
                        s = cs.Values[0] + (ExternalHelper.Helper.registryEntryExistsInLocalMachine(cs.Values[0]) ? "" : "");
                        break;
                    }
                //Command - Message
                case "message":
                    {
                        s = StringHelper.ListOfStringToString(cs.Values, true);
                        break;
                    }
                //Command - runSQLCommand (Run Command From XML Config)
                case "runcommandline":
                    {
                        string imitate = (cs.Values.Count == 2 ? cs.Values[1] : "false");
                        if (cs.Values.Count > 1)
                        {
                            s = string.Format("Running Command Line:{0} You will need to check your own command window. This is UNMANAGED", cs.Values[0]);
                            RunShellCommandChooser(cs.Values[0], runAsUserName, runAsPassword, imitate);
                        }
                        else
                        {
                            s = string.Format("Running Command Line:{0} You will need to check your own command window. This is UNMANAGED", cs.Values[0]);
                            RunShellCommandChooser(cs.Values[0], runAsUserName, runAsPassword, "false");
                        }
                        break;
                    }
                //Command - runSQLScript (SQL in file)
                case "runsqlscript":
                    {
                        string sqlCommand = ExternalHelper.Helper.ReadAFile(cs.Values[0]);
                        string sqlConnString = (cs.Values.Count == 1 ? sqlConnectionString : cs.Values[1]);
                        s = string.Format("Running SQL Command {0} Using Connection:{1}",sqlCommand,sqlConnString);
                        #if DEBUG
                        #else
                        ExternalHelper.Helper.RunSqlCommand(sqlCommand, sqlConnString);
                        #endif
                        break;
                    }
                //Command - runSQLCommand (Run Command From XML Config)
                case "runsqlcommand":
                    {
                        string sqlCommand = cs.Values[0];
                        string sqlConnString = (cs.Values.Count == 1 ? sqlConnectionString : cs.Values[1]);
                        s = string.Format("Running SQL Command {0} Using Connection:{1}", cs.Values[0], (cs.Values.Count == 1 ? sqlConnectionString : cs.Values[1]));
                        #if DEBUG
                        #else
                        ExternalHelper.Helper.RunSqlCommand(sqlCommand, sqlConnString);
                        #endif
                        break;
                    }
                //Command - runIfServiceExists
                case "runifserviceexists":
                    {
                        string imitate = (cs.Values.Count == 3 ? cs.Values[2] : "false");
                        if (cs.Values.Count == 2 || cs.Values.Count == 3)
                        {
                            if (cs.Values[0].Contains("::"))
                            {
                                if (ExternalHelper.Helper.isServiceInstalled(cs.Values[0].Substring(0, cs.Values[0].IndexOf("::")).Trim(), bool.Parse((cs.Values[0].Substring(cs.Values[0].IndexOf("::") + 2).Trim()))))
                                {
                                    RunShellCommandChooser(cs.Values[1], runAsUserName, runAsPassword, imitate);
                                    s = string.Format("{0} was found.\nRunning Command Line:{1} You will need to check your own command window. This is UNMANAGED",cs.Values[0].Substring(0, cs.Values[0].IndexOf("::")).Trim(),cs.Values[1]);
                                }
                                else
                                {
                                    s = string.Format("Service Not Found: {0}"+ cs.Values[0].Substring(0, cs.Values[0].IndexOf("::")).Trim());
                                }
                            }
                            else
                            {
                                if (ExternalHelper.Helper.isServiceInstalled(cs.Values[0].Trim(),false))
                                {
                                    RunShellCommandChooser(cs.Values[1], runAsUserName, runAsPassword, imitate);
                                      s = string.Format("{0} was found.\nRunning Command Line:{1} You will need to check your own command window. This is UNMANAGED",cs.Values[0].Trim(),cs.Values[1]);
                                }
                                else
                                {
                                    s = string.Format("Service Not Found: {0}",cs.Values[0].Trim());
                                }
                            }
                        }
                        else
                        { 
                            s = string.Format("runIfServiceExists takes 2 to 3 values\nYou have {0}",(cs.Values.Count));
                        }
                        break;
                    }
                //Command - runIfProgramInstalled
                case "runifprograminstalled":
                    {
                        string imitate = (cs.Values.Count == 3 ? cs.Values[2] : "false");
                        if (cs.Values.Count == 2 || cs.Values.Count == 3)
                        {
                            if (cs.Values[0].Contains("::"))
                            {
                                if (ExternalHelper.Helper.isInstalled(cs.Values[0].Substring(0, cs.Values[0].IndexOf("::")).Trim(), bool.Parse((cs.Values[0].Substring(cs.Values[0].IndexOf("::") + 2).Trim()))))
                                {
                                    RunShellCommandChooser(cs.Values[1], runAsUserName, runAsPassword, imitate);
                                     s = string.Format("{0} was found.\nRunning Command Line:{1} You will need to check your own command window. This is UNMANAGED",cs.Values[0].Substring(0, cs.Values[0].IndexOf("::")).Trim(),cs.Values[1]);
                                }
                                else
                                {
                                    s = "Program Not Found:" + cs.Values[0].Substring(0, cs.Values[0].IndexOf("::")).Trim();
                                }
                            }
                            else
                            {
                                if (ExternalHelper.Helper.isInstalled(cs.Values[0].Trim(), false))
                                {
                                    RunShellCommandChooser(cs.Values[1], runAsUserName, runAsPassword, imitate);
                                     s = string.Format("{0} was found.\nRunning Command Line:{1} You will need to check your own command window. This is UNMANAGED",cs.Values[0].Trim(),cs.Values[1]);
                                }
                                else
                                {
                                    s = "Program Not Found:" + cs.Values[0].Trim();
                                }
                            }
                        }
                        else
                        {
                            s = string.Format("runIfServiceExists takes 2 to 3 values\nYou have {0}", (cs.Values.Count));
                        }
                        break;
                    }
                //Command - runIfRegistryExists
                case "runifregistryexists":
                    {
                        string imitate = (cs.Values.Count == 3 ? cs.Values[2] : "false");
                        if (ExternalHelper.Helper.registryEntryExistsInLocalMachine(cs.Values[0].Trim()))
                        {
                            RunShellCommandChooser(cs.Values[1], runAsUserName, runAsPassword, imitate);
                            s = string.Format("{0} was found.\nRunning Command Line:{1} You will need to check your own command window. This is UNMANAGED",cs.Values[0].Trim(),cs.Values[1]);
                        }
                        else
                        {
                            s = string.Format("Registry Entry Not Found: {0}", cs.Values[0].Trim());
                        }
                        break;
                    }
                //Command - addXElement
                case "addxelement":
                    {
                        List<string> l = new List<string>();
                        if (cs.Values.Count >= 3)
                        {
                            s = string.Format("Adding XElement[{0}] to File:{1}", cs.Values[1], cs.Values[0]);
                            for (int i = 3; i < cs.Values.Count; i++)
                            {
                                ls.Add(cs.Values[i]);
                            }
                            s = XPathHelper.AddElementFromXPath(cs.Values[0], cs.Values[1], cs.Values[2], l);
                            ExternalHelper.Helper.WriteAFile(cs.Values[0], s, false);
       
                        }
                        else
                        {
                            string.Format("addXElement requires at least 3 parameters you supplied {0}.\n\t1.File Name\n\t2.XPath\n\t3.ElementToAdd In string format.\n\t 4+.(Optional) Namespace using Prefix::URN format", cs.Values.Count);
                        }
                        break;
                    }
                //Command - replaceOrAddXElementIfMissing
                case "replaceoraddxelementifmissing":
                    {
                        List<string> l = new List<string>();
                        if (cs.Values.Count >= 3)
                        {
                            s = string.Format("Adding/Editing XElement[{0}] to File:{1}", cs.Values[1], cs.Values[0]);
                            for (int i = 3; i < cs.Values.Count; i++)
                            {
                                ls.Add(cs.Values[i]);
                            }
                               s = XPathHelper.ReplaceOrAddIfMissingElementInElementUsingXPath(cs.Values[0], cs.Values[1], cs.Values[2], l);
                            ExternalHelper.Helper.WriteAFile(cs.Values[0],s,false);
                        
                        }
                        else
                        {
                            string.Format("addXElement requires at least 3 parameters you supplied {0}.\n\t1.File Name\n\t2.XPath\n\t3.ElementToAdd In string format.\n\t 4+.(Optional) Namespace using Prefix::URN format", cs.Values.Count);
                        }
                        break;
                    }
                //Command - replaceOrAddXAttributeIfMissing
                case "replaceoraddxattributeifmissing":
                    {
                        List<string> l = new List<string>();
                        if (cs.Values.Count >= 3)
                        {
                            s = string.Format("Adding/Editing Attribute [{0}] to File:{1}", cs.Values[1], cs.Values[0]);
                            for (int i = 3; i < cs.Values.Count; i++)
                            {
                                ls.Add(cs.Values[i]);
                            }
                            XElement xe = XElement.Load(cs.Values[0]);
                            s = XPathHelper.EditAttributeInXPath(cs.Values[0], cs.Values[1], cs.Values[2], l);
                            #if DEBUG
                            #else                          
                            ExternalHelper.Helper.WriteAFile(cs.Values[0],s,false);
                            #endif
                        }
                        else
                        {
                            string.Format("addXElement requires at least 3 parameters you supplied {0}.\n\t1.File Name\n\t2.XPath\n\t3.ElementToAdd In string format.\n\t 4+.(Optional) Namespace using Prefix::URN format", cs.Values.Count);
                        }
                        break;
                    }
            }
            return s;
        }
        private static void RunShellCommandChooser(string commandLine, string runAsUserName, string runAsPassword, string imitate)
        {
        #if DEBUG
        #else
            //If Run As Current User
            bool runAsOtherUser = false;
            if (string.IsNullOrEmpty(runAsUserName) || string.IsNullOrEmpty(runAsPassword) || !bool.TryParse(imitate, out runAsOtherUser))
            {   

                    ExternalHelper.Helper.RunShellCommand(commandLine);
            }
            else
            {
                if (runAsOtherUser)
                {
                    ExternalHelper.Helper.RunShellCommand(commandLine, runAsUserName, runAsPassword);

                }
                else
                {
                    ExternalHelper.Helper.RunShellCommand(commandLine);
                }
            }
        #endif
        }
        public static DeploymentObject DeploymentObjectFactory(XElement xe)
        {
            DeploymentObject DeployThis = new DeploymentObject();
            DeployThis.is64Bit = System.Environment.Is64BitOperatingSystem;
            DeployThis.Name = xe.Attribute("name").Value;
            if (xe.Attribute("allowFastDeploy") != null)
            {
                DeployThis.FastDeploy = bool.Parse(xe.Attribute("allowFastDeploy").Value);
            }
            List<string> Errors = new List<string>();
            CommandSet cs = new CommandSet();
            string file = string.Empty;
            foreach (XElement PreparedApp in xe.Elements("PrepareCommands").Elements("PreparedApp"))
            {
                file = PreparedApp.Element("File").Value;
                if (ExternalHelper.Helper.isFileInLocation(ref file))
                {
                    DeployThis.PreparedApps.Add(PreparedApp.Element("Name").Value, file.Trim());
                }
                else
                {
                    DeployThis.PreparedApps.Add(PreparedApp.Element("Name").Value, "Missing Value");
                }
            }
            //.OrderBy(x => x.Attribute("priority"))
            foreach (XElement commandSet in xe.Elements("Commands").Elements("CommandSet"))
            {
                cs = new CommandSet();
                if (commandSet.Element("Command").Value != null)
                {
                    List<string> commandList = StringHelper.StringToListOfString(commandSet.Element("Command").Value, "::", true, true);
                    cs.Command = commandList[0];
                    if (commandList.Count > 1)
                    {
                        cs.CommandTrigger = commandList[1];
                    }
                }
                if (commandSet.Element("Part").Value != null)
                {
                    List<string> partList =StringHelper.StringToListOfString(commandSet.Element("Part").Value, "::", true, true);
                    cs.Part = partList[0];
                    if (partList.Count > 1)
                    {
                        cs.PartTrigger = partList[1];
                    }
                }
                int i;
                if (!Int32.TryParse(commandSet.Attribute("priority").Value, out i))
                {
                    i = 0;
                }
                cs.Priority = ((commandSet.Attribute("priority") == null) ? 0 : Int32.Parse(commandSet.Attribute("priority").Value));
                cs.Description = ((commandSet.Element("Description") == null) ? string.Empty : commandSet.Element("Description").Value);
                cs.Error = ((commandSet.Element("Error") == null) ? string.Empty : commandSet.Element("Error").Value);
                cs.Success = ((commandSet.Element("Success") == null) ? string.Empty : commandSet.Element("Success").Value);
                foreach (XElement value in commandSet.Elements("Values").Elements("Value"))
                {
                    Errors.Clear();
                    if (value != null)
                    {
                        cs.Values.Add(StringHelper.FormatAutoDeployValue(value.Value, DeployThis.PreparedApps, ref Errors));
                    }
                    foreach (string e in Errors)
                    {
                        DeployThis.Errors.Add(e);
                    }
                }
                DeployThis.CommandSets.Add(cs);
            }
            return DeployThis;
        }
        public static List<CommandValuesView> LoadCommandValuesView(DeploymentObject ado)
        {
            return (from cs in ado.CommandSets
                    from value in cs.Values
                   select new CommandValuesView()
                   {
                      Command = cs.Command,
                      Priority = cs.Priority,
                      Value = value,
                      Run = true
                   }).ToList();
        }
        public static bool ValidateDeploymentObject(ref DeploymentObject ado)
        {
            ado.CommandSets.OrderBy(x => x.Priority);
            if (ado.CommandSets.Count != ado.CommandSets[ado.CommandSets.Count - 1].Priority)
            {
                return false;
            }
            return true;
        }
    }
}
